home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / smtpcli.c < prev    next >
Text File  |  1989-01-26  |  21KB  |  996 lines

  1.  
  2. /*
  3.  *    Client routines for Simple Mail Transfer Protocol ala RFC821
  4.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  5.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  6.  *    Permission granted for non-commercial copying and use, provided
  7.  *    this notice is retained.
  8.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  9.  *    also rebuilt locking mechanism
  10.  *    Limit on max simultaneous sessions, reuse of connections - 12/87 NN2Z
  11.  *    Added return of mail to sender as well as batching of commands 1/88 nn2z
  12.  */
  13. #include <stdio.h>
  14. #include "global.h"
  15. #ifdef MAC
  16. #include <io.h>
  17. #include <types.h>
  18. #else
  19. #include <fcntl.h>
  20. #include "io.h"
  21. #endif
  22. #include <time.h>
  23. #ifdef UNIX
  24. #include <sys/types.h>
  25. #endif
  26. #include "netuser.h"
  27. #include "mbuf.h"
  28. #include "timer.h"
  29. #include "tcp.h"
  30. #include "smtp.h"
  31. #include "trace.h"
  32. #include "cmdparse.h"
  33.  
  34. extern int16 lport;            /* local port placeholder */
  35. extern int32 resolve();
  36. static struct timer smtpcli_t;
  37. int32 gateway;
  38.  
  39. #ifdef SMTPTRACE
  40. int16    smtptrace = 0;            /* used for trace level */
  41. int dosmtptrace();
  42. #endif
  43.  
  44. int16    smtpmaxcli  = MAXSESSIONS;    /* the max client connections allowed */
  45. int16    smtpsessions = 0;        /* number of client connections
  46.                     * currently open */
  47. int16    smtpmode = 0;
  48.  
  49. static struct smtp_cb *cli_session[MAXSESSIONS]; /* queue of client sessions  */
  50.  
  51. static char quitcmd[] = "QUIT\r\n";
  52. static char eom[] = "\r\n.\r\n";
  53.  
  54. int smtptick(),dogateway(),dosmtpmaxcli(),mlock(),dotimer(),nextjob();
  55. int setsmtpmode(),sendwindow();
  56. void quit(),abort_trans(),retmail(),sendit(),del_session(),del_job();
  57. void execjobs(),smtp_transaction(),logerr();
  58. struct smtp_cb *newcb(),*lookup();
  59. struct smtp_job *setupjob();
  60.  
  61. struct cmds smtpcmds[] = {
  62.     "gateway",    dogateway,    0,    NULLCHAR,    NULLCHAR,
  63.     "mode",        setsmtpmode,    0,    NULLCHAR,    NULLCHAR,
  64.     "kick",        smtptick,    0,    NULLCHAR,    NULLCHAR,
  65.     "maxclients",    dosmtpmaxcli,    0,    NULLCHAR,    NULLCHAR,
  66.     "timer",    dotimer,    0,    NULLCHAR,    NULLCHAR,
  67. #ifdef SMTPTRACE
  68.     "trace",    dosmtptrace,    0,    NULLCHAR,    NULLCHAR,
  69. #endif
  70.     NULLCHAR,    NULLFP,        0,    
  71.     "subcommands: gateway kick maxclients timer trace",
  72.         NULLCHAR,
  73. };
  74.  
  75. dosmtp(argc,argv)
  76. int argc;
  77. char *argv[];
  78. {
  79.     return subcmd(smtpcmds,argc,argv);
  80. }
  81.  
  82. static int
  83. dosmtpmaxcli(argc,argv)
  84. int argc;
  85. char *argv[];
  86. {
  87.     int x;
  88.     if (argc < 2)
  89.         printf("%d\n",smtpmaxcli);
  90.     else {
  91.         x = atoi(argv[1]);
  92.         if (x > MAXSESSIONS)
  93.             printf("max clients must be <= %d\n",MAXSESSIONS);
  94.         else
  95.             smtpmaxcli = x;
  96.     }
  97.     return 0;
  98. }
  99.  
  100. static int
  101. setsmtpmode(argc,argv)
  102. int argc;
  103. char *argv[];
  104. {
  105.     if (argc < 2) {
  106.         printf("smtp mode: %s\n",
  107.             (smtpmode & QUEUE) ? "queue" : "route");
  108.     } else {
  109.         switch(*argv[1]) {
  110.         case 'q':
  111.             smtpmode |= QUEUE;
  112.             break;
  113.         case 'r':
  114.             smtpmode &= ~QUEUE;
  115.             break;
  116.         default:
  117.             printf("Usage: smtp mode [queue | route]\n");
  118.             break;
  119.         }
  120.     }
  121.     return 0;
  122. }
  123. static int
  124. dogateway(argc,argv)
  125. int argc;
  126. char *argv[];
  127. {
  128.     char *inet_ntoa();
  129.     int32 n;
  130.     extern char badhost[];
  131.  
  132.     if(argc < 2){
  133.         printf("%s\n",inet_ntoa(gateway));
  134.     } else if((n = resolve(argv[1])) == 0){
  135.         printf(badhost,argv[1]);
  136.         return 1;
  137.     } else
  138.         gateway = n;
  139.     return 0;
  140. }
  141.  
  142. #ifdef SMTPTRACE
  143. static int
  144. dosmtptrace(argc,argv)
  145. int argc;
  146. char *argv[];
  147. {
  148.     if (argc < 2)
  149.         printf("%d\n",smtptrace);
  150.     else 
  151.         smtptrace = atoi(argv[1]);
  152.     return 0;
  153. }
  154. #endif
  155.  
  156. /* Set outbound spool poll interval */
  157. static int
  158. dotimer(argc,argv)
  159. int argc;
  160. char *argv[];
  161. {
  162.     int smtptick();
  163.  
  164.     if(argc < 2){
  165.         printf("%lu/%lu\n",
  166.         (smtpcli_t.start - smtpcli_t.count)/(1000/MSPTICK),
  167.         smtpcli_t.start/(1000/MSPTICK));
  168.         return 0;
  169.     }
  170.     smtpcli_t.func = (void (*)())smtptick;/* what to call on timeout */
  171.     smtpcli_t.arg = NULLCHAR;        /* dummy value */
  172.     smtpcli_t.start = atoi(argv[1])*(1000/MSPTICK);    /* set timer duration */
  173.     start_timer(&smtpcli_t);        /* and fire it up */
  174.     return 0;
  175. }
  176.  
  177. /* this is the routine that gets called every so often to do outgoing mail
  178.    processing */
  179. int
  180. smtptick()
  181. {
  182.     register struct smtp_cb *cb;
  183.     struct smtp_job *jp;
  184.     struct list *ap;
  185.     char    tmpstring[LINELEN], wfilename[13], prefix[9];
  186.     char    from[LINELEN], to[LINELEN];
  187.     char *cp, *cp1;
  188.     int32 destaddr;
  189.     FILE *wfile;
  190.  
  191. #ifdef SMTPTRACE
  192.     if (smtptrace > 5) {
  193.         printf("smtp daemon entered\n");
  194.         fflush(stdout);
  195.     }
  196. #endif
  197.     for(filedir(mailqueue,0,wfilename);wfilename[0] != '\0';
  198.         filedir(mailqueue,1,wfilename)){
  199.  
  200.         /* save the prefix of the file name which it job id */
  201.         cp = wfilename;
  202.         cp1 = prefix;
  203.         while (*cp && *cp != '.')
  204.             *cp1++ = *cp++;
  205.         *cp1 = '\0';
  206.  
  207.         /* lock this file from the smtp daemon */
  208.         if (mlock(mailqdir,prefix))
  209.             continue;
  210.  
  211.         sprintf(tmpstring,"%s%c%s",mailqdir,PATH_DELIM,wfilename);
  212.         if ((wfile = fopen(tmpstring,"r")) == NULLFILE) {
  213.             /* probably too many open files */
  214.             (void) rmlock(mailqdir,prefix);
  215.             /* continue to next message. The failure
  216.             * may be temporary */
  217.             continue;
  218.         }
  219.  
  220.         (void) fgets(tmpstring,LINELEN,wfile);    /* read target host */
  221.         rip(tmpstring);
  222.  
  223.         if ((destaddr = mailroute(tmpstring)) == 0) {
  224.             fclose(wfile);
  225.             printf("** smtp: Unknown address %s\n",tmpstring);
  226.             fflush(stdout);
  227.             (void) rmlock(mailqdir,prefix);
  228.             continue;
  229.         }
  230.  
  231.         if ((cb = lookup(destaddr)) == NULLCB) {
  232.             /* there are enough processes running already */
  233.             if (smtpsessions >= smtpmaxcli) {
  234. #ifdef SMTPTRACE
  235.                 if (smtptrace) {
  236.                     printf("smtp daemon: too many processes\n");
  237.                     fflush(stdout);
  238.                 }
  239. #endif
  240.                 fclose(wfile);
  241.                 (void) rmlock(mailqdir,prefix);
  242.                 break;
  243.             }
  244.             if ((cb = newcb()) == NULLCB) {
  245.                 fclose(wfile);
  246.                 (void) rmlock(mailqdir,prefix);
  247.                 break;
  248.             } 
  249.             cb->ipdest = destaddr;
  250.         } else {
  251.             /* This system is already is sending mail lets not
  252.             * interfere with its send queue.
  253.             */
  254.             if (cb->state != CLI_INIT_STATE) {
  255.                 fclose(wfile);
  256.                 (void) rmlock(mailqdir,prefix);
  257.                 continue;
  258.             }
  259.         }
  260.  
  261.         (void) fgets(from,LINELEN,wfile);    /* read from */
  262.         rip(from);
  263.         if ((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  264.             fclose(wfile);
  265.             (void) rmlock(mailqdir,prefix);
  266.             del_session(cb);
  267.             break;
  268.         }
  269.         while (fgets(to,LINELEN,wfile) != NULLCHAR) {
  270.             rip(to);
  271.             if (addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  272.                 fclose(wfile);
  273.                 del_session(cb);
  274.             }
  275.         }
  276.         fclose(wfile);
  277. #ifdef SMTPTRACE
  278.         if (smtptrace > 1) {
  279.             printf("queue job %s From: %s To:",prefix,from);
  280.             for (ap = jp->to; ap != NULLLIST; ap = ap->next)
  281.                 printf(" %s",ap->val);
  282.             printf("\n");
  283.             fflush(stdout);
  284.         }
  285. #endif
  286.     }
  287.  
  288.     /* start sending that mail */
  289.     execjobs();
  290.  
  291.     /* Restart timer */
  292.     start_timer(&smtpcli_t);
  293. }
  294.  
  295. /* this is the master state machine that handles a single SMTP transaction */
  296. void
  297. smtp_transaction(cb)
  298. register struct smtp_cb *cb;
  299. {
  300.     void smtp_cts();
  301.     register char reply;
  302.     register struct list *tp;
  303.     int16 cnt;
  304.     struct mbuf *bp,*bpl;
  305.     char tbuf[LINELEN];
  306.     int rcode;
  307.  
  308. #ifdef SMTPTRACE
  309.     if (smtptrace > 5) 
  310.         printf("smtp_transaction() enter state=%u\n",cb->state);
  311.     if (smtptrace) {
  312.         printf("%s\n",cb->buf);
  313.         fflush(stdout);
  314.     }
  315. #endif
  316.     /* Another line follows; ignore this one */
  317.     if(cb->buf[0] == '0' || cb->buf[3] == '-')
  318.         return;
  319.  
  320.     reply = cb->buf[0];
  321.     rcode = atoi(cb->buf);
  322.  
  323.     /* if service shuting down */
  324.     if (rcode == 421) {
  325.         quit(cb);
  326.         return;
  327.     }
  328.  
  329.     switch(cb->state) {
  330.     case CLI_OPEN_STATE:
  331.         if (reply != '2')
  332.             quit(cb);
  333.         else {
  334.             cb->state = CLI_HELO_STATE;
  335.             sendit(cb,"HELO %s\r\nMAIL FROM:<%s>\r\n",
  336.             hostname,cb->jobq->from);
  337.         }
  338.         break;
  339.     case CLI_HELO_STATE:
  340.         if (reply != '2')
  341.             quit(cb);
  342.         else 
  343.             cb->state = CLI_MAIL_STATE;
  344.         break;            
  345.     case CLI_MAIL_STATE:
  346.         if (reply != '2')
  347.             quit(cb);
  348.         else {
  349.             cb->state = CLI_RCPT_STATE;
  350.             cb->rcpts = 0;
  351.             bpl = NULLBUF;
  352.             for (tp = cb->jobq->to; tp != NULLLIST; tp = tp->next){
  353.                 sprintf(tbuf,"RCPT TO:<%s>\r\n",tp->val);
  354.                 bp = qdata(tbuf,(int16)strlen(tbuf));
  355.                 if (bp == NULLBUF) {
  356.                     free_p(bpl);
  357.                     quit(cb);
  358.                     return;
  359.                 }
  360.                 append(&bpl,bp);
  361.                 cb->rcpts++;
  362. #ifdef SMTPTRACE
  363.                 if (smtptrace) {
  364.                     printf(">>> %s",tbuf);
  365.                     fflush(stdout);
  366.                 }
  367. #endif
  368.             }
  369.             send_tcp(cb->tcb,bpl);
  370.         }
  371.         break;
  372.     case CLI_RCPT_STATE:
  373.         if (reply == '5') {
  374.             logerr(cb);
  375.         } else if (reply == '2') {
  376.             cb->goodrcpt =1;
  377.         } else {
  378.             /* some kind of temporary failure */
  379.             abort_trans(cb);
  380.             break;
  381.         }
  382.         /* if more rcpts stay in this state */
  383.         if (--cb->rcpts != 0)
  384.             break;
  385.  
  386.         /* check for no good rcpt on the list */
  387.         if (cb->goodrcpt == 0) {
  388.             if (cb->errlog != NULLLIST)
  389.                 retmail(cb);
  390.             (void) unlink(cb->wname);    /* unlink workfile */
  391.             (void) unlink(cb->tname);    /* unlink text */
  392.             abort_trans(cb);
  393.             break;
  394.         }
  395.         /* if this file open fails abort */
  396.         if ((cb->tfile = fopen(cb->tname,"r")) == NULLFILE)
  397.             abort_trans(cb);
  398.         else {
  399.             /* optimize for slow packet links by sending
  400.              * DATA cmd and the 1st window of text
  401.              */
  402.             if (cb->tcb->window <= cb->tcb->sndcnt)
  403.                 cnt = 0;
  404.             else
  405.                 cnt = cb->tcb->window - cb->tcb->sndcnt;
  406.             bp = qdata("DATA\r\n",6);
  407.             cb->cts = 1;
  408.             cb->state = CLI_SEND_STATE;
  409.             if (sendwindow(cb,bp,cnt) == EOF)
  410.                 cb->cts = 0;
  411.         }
  412.         break;
  413.     case CLI_SEND_STATE:
  414.         if (reply == '3') {
  415.             cb->state = CLI_UNLK_STATE;
  416.         } else {
  417.             /* change cts to transmit upcall queueing more data */
  418.             cb->cts = 0;
  419.             quit(cb);
  420.         }
  421.         break;
  422.     case CLI_UNLK_STATE:
  423.         /* if a good transfer or permanent failure remove job */
  424.         if (reply == '2' || reply == '5') {
  425.             if (reply == '5')
  426.                 logerr(cb);
  427.             /* close and unlink the textfile */
  428.             if(cb->tfile != NULLFILE) {
  429.                 fclose(cb->tfile);
  430.                 cb->tfile = NULLFILE;
  431.             }
  432.             if (cb->errlog != NULLLIST)
  433.                 retmail(cb);
  434.             (void) unlink(cb->tname);
  435.             (void) unlink(cb->wname);    /* unlink workfile */
  436.             log(cb->tcb,"SMTP sent job %s To: %s From: %s",
  437.             cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  438.         }
  439.         if (nextjob(cb)) {
  440.             cb->state = CLI_MAIL_STATE;
  441.             sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  442.         } else 
  443.             /* the quit sent already in smtp_cts */
  444.             cb->state = CLI_QUIT_STATE;
  445.         break;
  446.     case CLI_IDLE_STATE:    /* used after a RSET and more mail to send */
  447.         if (reply != '2')
  448.             quit(cb);
  449.         else {
  450.             cb->state = CLI_MAIL_STATE;
  451.             sendit(cb,"MAIL FROM:<%s>\r\n",cb->jobq->from);
  452.         }
  453.         break;            
  454.     case CLI_QUIT_STATE:
  455.         break;
  456.     }
  457. }
  458.  
  459. /* abort the currrent job.
  460.  * If more work exists set up the next job if
  461.  * not then shut down.
  462. */
  463. static void
  464. abort_trans(cb)
  465. register struct smtp_cb *cb;
  466. {
  467.     if(cb->tfile != NULLFILE) {
  468.         fclose(cb->tfile);
  469.         cb->tfile = NULLFILE;
  470.     }
  471.     if (nextjob(cb)) {
  472.         sendit(cb,"RSET\r\n");
  473.         cb->state = CLI_IDLE_STATE;
  474.     } else 
  475.         quit(cb);
  476. }
  477.  
  478. /* close down link after a failure */
  479. static void
  480. quit(cb)
  481. struct smtp_cb *cb;
  482. {
  483.     cb->state = CLI_QUIT_STATE;
  484.     sendit(cb,quitcmd);        /* issue a quit command */
  485.     close_tcp(cb->tcb);        /* close up connection */
  486. }
  487.  
  488. /* smtp receiver upcall routine.  fires up the state machine to parse input */
  489. static
  490. void
  491. smtp_rec(tcb,cnt)
  492. struct tcb *tcb;
  493. int16 cnt;
  494. {
  495.     register struct smtp_cb *cb;
  496.     char *inet_ntoa();
  497.     char c;
  498.     struct mbuf *bp;
  499.  
  500. #ifdef SMTPTRACE
  501.     if (smtptrace > 7)  {
  502.         printf("smtp_rec called\n");
  503.         fflush(stdout);
  504.     }
  505. #endif
  506.     cb = (struct smtp_cb *)tcb->user;    /* point to our struct */
  507.     recv_tcp(tcb,&bp,cnt);    /* suck up chars from low level routine */
  508.  
  509.     /* Assemble input line in buffer, return if incomplete */
  510.     while(pullup(&bp,&c,1) == 1) {
  511.         switch(c) {
  512.         case '\r':    /* strip cr's */
  513.             continue;
  514.         case '\n':    /* line is finished, go do it! */
  515.             cb->buf[cb->cnt] = '\0';
  516.             smtp_transaction(cb);
  517.             cb->cnt = 0;
  518.             break;
  519.         default:    /* other chars get added to buffer */
  520.             if(cb->cnt != LINELEN-1)
  521.                 cb->buf[cb->cnt++] = c;
  522.             break;
  523.         }
  524.     }
  525. }
  526.  
  527. /* smtp transmitter ready upcall routine.  twiddles cts flag */
  528. static 
  529. void
  530. smtp_cts(tcb,cnt)
  531. struct tcb *tcb;
  532. int16 cnt;
  533. {
  534.     register struct smtp_cb *cb;
  535.  
  536. #ifdef SMTPTRACE
  537.     if (smtptrace > 7) {
  538.         printf("smtp_cts called avail %d\n",cnt);
  539.         fflush(stdout);
  540.     }
  541. #endif
  542.     cb = (struct smtp_cb *)tcb->user;    /* point to our struct */
  543.  
  544.     /* don't do anything until/unless we're supposed to be sending */
  545.     if(cb->cts == 0)
  546.         return;
  547.  
  548.     if (sendwindow(cb,NULLBUF,cnt) == EOF)
  549.         cb->cts = 0;
  550. }
  551.  
  552. /* fill the rest of the window with data and send out the eof commands.
  553. * It is done this way to minimize the number of packets sent.
  554. */
  555. static int
  556. sendwindow(cb,ibp,cnt)
  557. register struct smtp_cb *cb;
  558. struct mbuf *ibp;
  559. int16 cnt;
  560. {
  561.     struct mbuf *bpl;
  562.     register struct mbuf *bp;
  563.     char *cp;
  564.     int c;
  565.     
  566.     bpl = ibp;
  567.     if((bp = alloc_mbuf(cnt)) == NULLBUF){
  568.         /* Hard to know what to do here */
  569.         return EOF;
  570.     }
  571.     cp = bp->data;
  572.     while(cnt > 1 && (c = getc(cb->tfile)) != EOF){
  573. #if (defined(UNIX) || defined(MAC) || defined(AMIGAa))
  574.         if(c == '\n'){
  575.             *cp++ = '\r';
  576.             bp->cnt++;
  577.             cnt--;
  578.         }
  579. #endif
  580.         *cp++ = c;
  581.         bp->cnt++;
  582.         cnt--;
  583.     }
  584.     append(&bpl,bp);
  585.     if (cnt > 1) {    /* EOF seen */
  586.         fclose(cb->tfile);
  587.         cb->tfile = NULLFILE;
  588.         /* send the end of data character. */
  589.         if (cnt < sizeof(eom) - 1) {
  590.             bp = qdata(eom,5);
  591.             append(&bpl,bp);
  592.             cnt = 0;    /* dont let anyone else in */
  593.         } else {
  594.             memcpy(&bp->data[bp->cnt],eom,sizeof(eom) - 1);
  595.             bp->cnt += sizeof(eom) - 1;
  596.             cnt -= sizeof(eom) - 1;
  597.         }
  598.         /* send the quit in this packet if last job */
  599.         if (cb->jobq->next == NULLJOB) {
  600.             if (cnt < sizeof(quitcmd) - 1) {
  601.                 bp = qdata(quitcmd,sizeof(quitcmd) - 1);
  602.                 append(&bpl,bp);
  603.             } else {
  604.                 memcpy(&bp->data[bp->cnt],
  605.                 quitcmd,sizeof(quitcmd) - 1);
  606.                 bp->cnt += sizeof(quitcmd) - 1;
  607.             }
  608.         }
  609.         send_tcp(cb->tcb,bpl);
  610.         if (cb->jobq->next == NULLJOB)
  611.             close_tcp(cb->tcb);    /* close up connection */
  612.         return EOF;
  613.     } else {
  614.         send_tcp(cb->tcb,bpl);
  615.         return 0;
  616.     }
  617. }
  618.  
  619. /* smtp state change upcall routine. */
  620. static
  621. void
  622. smtp_state(tcb,old,new)
  623. register struct tcb *tcb;
  624. char old,new;
  625. {
  626.     register struct smtp_cb *cb;
  627.     extern char *tcpstates[];
  628.  
  629. #ifdef SMTPTRACE
  630.     if (smtptrace > 7) {
  631.         printf("smtp_state called: %s\n",tcpstates[new]);
  632.         fflush(stdout);
  633.     }
  634. #endif
  635.     cb = (struct smtp_cb *)tcb->user;
  636.     switch(new) {
  637.     case ESTABLISHED:
  638.         cb->state = CLI_OPEN_STATE;    /* shouldn't be needed */
  639.         break;
  640.     case CLOSE_WAIT:
  641.         close_tcp(tcb);            /* shut things down */
  642.         break;
  643.     case CLOSED:
  644.         /* if this close was not done by us ie. a RST */
  645.         if(cb->tfile != NULLFILE)
  646.             fclose(cb->tfile);
  647.         del_session(cb);
  648.         del_tcp(tcb);
  649.         break;
  650.     }
  651. }
  652.  
  653. /* Send message back to server */
  654. /*VARARGS*/
  655. static void
  656. sendit(cb,fmt,arg1,arg2)
  657. struct smtp_cb *cb;
  658. char *fmt,*arg1,*arg2;
  659. {
  660.     struct mbuf *bp;
  661.     char tmpstring[256];
  662.  
  663. #ifdef SMTPTRACE
  664.     if (smtptrace) {
  665.         printf(">>> ");
  666.         printf(fmt,arg1,arg2);
  667.         fflush(stdout);
  668.     }
  669. #endif
  670.     sprintf(tmpstring,fmt,arg1,arg2);
  671.     bp = qdata(tmpstring,(int16)strlen(tmpstring));
  672.     send_tcp(cb->tcb,bp);
  673. }
  674.  
  675. /* create mail lockfile */
  676. int
  677. mlock(dir,id)
  678. char *dir,*id;
  679. {
  680.     char lockname[LINELEN];
  681.     int fd;
  682.     /* Try to create the lock file in an atomic operation */
  683.     sprintf(lockname,"%s%c%s.lck",dir,PATH_DELIM,id);
  684.     if((fd = open(lockname, O_WRONLY|O_EXCL|O_CREAT,0600)) == -1)
  685.         return -1;
  686.     close(fd);
  687.     return 0;
  688. }
  689.  
  690. /* remove mail lockfile */
  691. int
  692. rmlock(dir,id)
  693. char *dir,*id;
  694. {
  695.     char lockname[LINELEN];
  696.     sprintf(lockname,"%s%c%s.lck",dir,PATH_DELIM,id);
  697.     return(unlink(lockname));
  698. }
  699.  
  700. /* free the message struct and data */
  701. static void
  702. del_session(cb)
  703. register struct smtp_cb *cb;
  704. {
  705.     register struct smtp_job *jp,*tp;
  706.     register int i;
  707.  
  708.     if (cb == NULLCB)
  709.         return;
  710.     for(i=0; i<MAXSESSIONS; i++) 
  711.         if(cli_session[i] == cb) {
  712.             cli_session[i] = NULLCB;
  713.             break;
  714.         }
  715.  
  716.     if(cb->wname != NULLCHAR)
  717.         free(cb->wname);
  718.     if(cb->tname != NULLCHAR)
  719.         free(cb->tname);
  720.     for (jp = cb->jobq; jp != NULLJOB;jp = tp) {
  721.             tp = jp->next;
  722.             del_job(jp);
  723.     }
  724.     del_list(cb->errlog);
  725.     free((char *)cb);
  726.     smtpsessions--;    /* number of connections active */
  727. }
  728.  
  729. void
  730. del_job(jp)
  731. register struct smtp_job *jp;
  732. {
  733.     if ( *jp->jobname != '\0')
  734.         (void) rmlock(mailqdir,jp->jobname);
  735.     if(jp->from != NULLCHAR)
  736.         free(jp->from);
  737.     del_list(jp->to);
  738.     free((char *)jp);
  739. }
  740.  
  741. /* delete a list of list structs */
  742. void
  743. del_list(lp)
  744. struct list *lp;
  745. {
  746.     register struct list *tp, *tp1;
  747.     for (tp = lp; tp != NULLLIST; tp = tp1) {
  748.             tp1 = tp->next;
  749.             if(tp->val != NULLCHAR)
  750.                 free(tp->val);
  751.             free((char *)tp);
  752.     }
  753. }
  754.  
  755. /* return message to sender */
  756. static void
  757. retmail(cb)
  758. struct smtp_cb *cb;
  759. {
  760.     register struct list *lp;
  761.     register FILE *tfile;
  762.     register int c;
  763.     FILE *infile,*tmpfile();
  764.     char *host,*to;
  765.      time_t t; 
  766. #ifdef SMTPTRACE
  767.     if (smtptrace > 5) {
  768.         printf("smtp job %s returned to sender\n",cb->wname);
  769.         fflush(stdout);
  770.     }
  771. #endif
  772.     /* A null From<> so no looping replys to MAIL-DAEMONS */
  773.     to = cb->jobq->from;
  774.     if (*to == '\0')
  775.         return;
  776.     if ((host = index(to,'@')) == NULLCHAR)
  777.         host = hostname;
  778.     else
  779.         host++;
  780.     if ((infile = fopen(cb->tname,"r")) == NULLFILE)
  781.         return;
  782.     if ((tfile = tmpfile()) == NULLFILE) {
  783.         fclose(infile);
  784.         return;
  785.     }
  786.     time(&t);
  787.     fprintf(tfile,"Date: %s",ptime(&t));
  788.     fprintf(tfile,"Message-Id: <%ld@%s>\n",get_msgid(),hostname);
  789.     fprintf(tfile,"From: MAILER-DAEMON@%s\n",hostname);
  790.     fprintf(tfile,"To: %s\n",to);
  791.     fprintf(tfile,"Subject: Failed mail\n\n");
  792.     fprintf(tfile,"  ===== transcript follows =====\n\n");
  793.  
  794.     for (lp = cb->errlog; lp != NULLLIST; lp = lp->next)
  795.         fprintf(tfile,"%s\n",lp->val);
  796.  
  797.     fprintf(tfile,"\n  ===== Unsent message follows ====\n");
  798.  
  799.     while((c = getc(infile)) != EOF)
  800.         if (putc(c,tfile) == EOF)
  801.             break;
  802.     fclose(infile);
  803.     fseek(tfile,0L,0);
  804.     if ((smtpmode & QUEUE) != 0)
  805.         router_queue(cb->tcb,tfile,"",to);
  806.     else
  807.         queuejob(cb->tcb,tfile,host,to,"");
  808.     fclose(tfile);
  809. }
  810.  
  811. /* look to see if a smtp control block exists for this ipdest */
  812. static struct smtp_cb *
  813. lookup(destaddr)
  814. int32 destaddr;
  815. {
  816.     register int i;
  817.  
  818.     for(i=0; i<MAXSESSIONS; i++) {
  819.         if (cli_session[i] == NULLCB)
  820.             continue;
  821.         if(cli_session[i]->ipdest == destaddr)
  822.             return cli_session[i];
  823.     }
  824.     return NULLCB;
  825. }
  826.  
  827. /* create a new  smtp control block */
  828. static struct smtp_cb *
  829. newcb()
  830. {
  831.     register int i;
  832.     register struct smtp_cb *cb;
  833.  
  834.     for(i=0; i<MAXSESSIONS; i++) {
  835.         if(cli_session[i] == NULLCB) {
  836.             cb = (struct smtp_cb *)calloc(1,sizeof(struct smtp_cb));
  837.             if (cb == NULLCB)
  838.                 return(NULLCB);
  839.             cb->wname = malloc((unsigned)strlen(mailqdir)+JOBNAME);
  840.             if (cb->wname == NULLCHAR) {
  841.                 free((char *)cb);
  842.                 return(NULLCB);
  843.             }
  844.             cb->tname = malloc((unsigned)strlen(mailqdir)+JOBNAME);
  845.             if (cb->tname == NULLCHAR) {
  846.                 free(cb->wname);
  847.                 free((char *)cb);
  848.                 return(NULLCB);
  849.             }
  850.             cb->state = CLI_INIT_STATE;
  851.             cli_session[i] = cb;
  852.             smtpsessions++;    /* number of connections active */
  853.             return(cb);
  854.         }
  855.     }
  856.     return NULLCB;
  857. }
  858.  
  859. static void
  860. execjobs()
  861. {
  862.     struct socket lsocket, fsocket;
  863.     void smtp_rec(), smtp_cts(), smtp_state();
  864.     register struct smtp_cb *cb;
  865.     register int i;
  866.  
  867.     for(i=0; i<MAXSESSIONS; i++) {
  868.         cb = cli_session[i];
  869.         if (cb == NULLCB) 
  870.             continue;
  871.         if(cb->state != CLI_INIT_STATE)
  872.             continue;
  873.  
  874.         sprintf(cb->tname,"%s%c%s.txt",mailqdir,PATH_DELIM,cb->jobq->jobname);
  875.         sprintf(cb->wname,"%s%c%s.wrk",mailqdir,PATH_DELIM,cb->jobq->jobname);
  876.  
  877.         /* setup the socket */
  878.         fsocket.address = cb->ipdest;
  879.         fsocket.port = SMTP_PORT;
  880.         lsocket.address = ip_addr;    /* our ip address */
  881.         lsocket.port = lport++;        /* next unused port */
  882. #ifdef SMTPTRACE
  883.         if (smtptrace) {
  884.             printf("Trying Connection to %s\n",inet_ntoa(fsocket.address));
  885.             fflush(stdout);
  886.         }
  887. #endif
  888.  
  889.         /* open smtp connection */
  890.         cb->state = CLI_OPEN_STATE;    /* init state placeholder */
  891.         cb->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,tcp_window,
  892.             smtp_rec,smtp_cts,smtp_state,0,(char *)cb);
  893.         cb->tcb->user = (char *)cb;    /* Upward pointer */
  894.     }
  895. }
  896.     
  897. /* add this job to control block queue */
  898. struct smtp_job *
  899. setupjob(cb,id,from)
  900. struct smtp_cb *cb;
  901. char *id,*from;
  902. {
  903.     register struct smtp_job *p1,*p2;
  904.  
  905.     p1 = (struct smtp_job *)calloc(1,sizeof(struct smtp_job));
  906.     if (p1 == NULLJOB)
  907.         return NULLJOB;
  908.     p1->from = malloc((unsigned)strlen(from) + 1);
  909.     if (p1->from == NULLCHAR) {
  910.         free((char *)p1);
  911.         return NULLJOB;
  912.     }
  913.     strcpy(p1->from,from);
  914.     strcpy(p1->jobname,id);
  915.     /* now add to end of jobq */
  916.     if ((p2 = cb->jobq) == NULLJOB)
  917.         cb->jobq = p1;
  918.     else {
  919.         while(p2->next != NULLJOB)
  920.             p2 = p2->next;
  921.         p2->next = p1;
  922.     }
  923.     return p1;
  924. }
  925.  
  926. /* called to advance to the next job */
  927. static int
  928. nextjob(cb)
  929. register struct smtp_cb *cb;
  930. {
  931.     register struct smtp_job *jp;
  932.  
  933.  
  934.     jp = cb->jobq->next;
  935.     del_job(cb->jobq);
  936.     if (jp == NULLJOB) {
  937.         cb->jobq = NULLJOB;
  938.         return 0;
  939.     }
  940.     /* remove the error log of previous message */
  941.     del_list(cb->errlog);
  942.     cb->errlog = NULLLIST;
  943.     cb->goodrcpt = 0;
  944.     cb->jobq = jp;
  945.     sprintf(cb->tname,"%s%c%s.txt",mailqdir,PATH_DELIM,jp->jobname);
  946.     sprintf(cb->wname,"%s%c%s.wrk",mailqdir,PATH_DELIM,jp->jobname);
  947. #ifdef SMTPTRACE
  948.     if (smtptrace > 5) {
  949.         printf("sending job %s\n",jp->jobname);
  950.         fflush(stdout);
  951.     }
  952. #endif
  953.         return 1;
  954.  
  955. }
  956.  
  957.  
  958. /* mail routing funtion. For now just used the hosts file */
  959. int32
  960. mailroute(dest)
  961. char *dest;
  962. {
  963.     int32 destaddr;
  964.  
  965.     /* look up address or use the gateway */
  966.     if ((destaddr = resolve(dest)) == 0)
  967.         if (gateway != 0) 
  968.             destaddr = gateway; /* Use the gateway  */
  969.     return destaddr;
  970.     
  971. }
  972.  
  973. /* save error reply for in error list */
  974. static void
  975. logerr(cb)
  976. struct smtp_cb *cb;
  977. {
  978.     register struct list *lp,*tp;
  979.     if ((tp = (struct list *)calloc(1,sizeof(struct list))) == NULLLIST)
  980.         return;
  981.     if ((tp->val = malloc((unsigned)strlen(cb->buf)+1)) == NULLCHAR) {
  982.         free((char *)tp);
  983.         return;
  984.     }
  985.     /* find end of list */
  986.     if ((lp = cb->errlog) == NULLLIST)
  987.         cb->errlog = tp;
  988.     else {
  989.         while(lp->next != NULLLIST)
  990.             lp = lp->next;
  991.         lp->next = tp;
  992.     }
  993.     strcpy(tp->val,cb->buf);
  994. }
  995.  
  996.